<?php
namespace Flow;

use Flow\models\XhflowAdvice;
use Phalcon\Di;
use Helpers\Hrm;
use Helpers\Main;
use Flow\models\XhflowProcess;
use Flow\models\XhflowNode;
use Flow\models\XhflowMainflow;
use Flow\models\XhflowFlownode;

class Flow extends Config
{

    private $moduleName;
    private $tableName;
    private $userId;

    function __construct($moduleName, $tableName = '')
    {
        if (!$moduleName) {
            throw new \Exception('模块名不能为空');
        }
        $this->moduleName = ucfirst($moduleName);
        $this->tableName = $tableName;
        $this->userId = Main::getLoginUserInfo('userId');
        if (!$this->userId) {
            throw new \Exception('当前未登录，不可操作');
        }
    }

//    private function runConfigParams(&$obj)
//    {
//        $obj['users']   = Hrm::getFlowDepStaff();
//        $obj['config']  = [
//            'namePrefix'    => self::NamePrefix,
//            'classPrefix'   => self::ClassPrefix
//        ];
//    }

    /**
     * 根据标签生成流程所需数据
     *
     * @param $tag
     * @return array
     * @throws \Exception
     *
     * create by ck 20171120
     */
    public function getFlowForNew($tag)
    {
        if (!$tag) {
            throw new \Exception('流程标识不能为空！');
        }

        //获取主流程模板
        $flowList = XhflowProcess::find([
            'columns' => 'iProId AS proId,sName AS proName',
            'conditions' => 'bDelete = 0 AND sTag = :tag:',
            'bind' => ['tag' => $tag]
        ])->toArray();
        if (!$flowList) {
            throw new \Exception('该标识下无流程模板');
        }
        $flowList = array_column($flowList, null, 'proId');

        //获取流程节点
        $processIds = array_keys($flowList);
        $nodeList = XhflowNode::find([
            'columns' => [
                'iProId AS proId',
                'iCode AS code',
                'sName AS nodeName',
                'sTargetUser AS targetUser',
                'sTargetArea AS targetArea',
                'bNeedAll AS needAll',
                'bImportant AS important'
            ],
            'conditions' => 'bDelete = 0 AND iProId IN ({proId:array})',
            'bind' => ['proId' => $processIds],
            'order' => 'iProId,iCode'
        ])->toArray();
        if (!$nodeList) {
            throw new \Exception('该标识下节点');
        }

        //流程组合，如为第一个节点则填充自身id
        foreach ($nodeList as $node) {
            if ($node['code'] == 1) {
                $node['targetUser'] = ",{$this->userId},";
            }
//            $mutable  = $node['targetUser'] ? 0 : 1;
            $nodeInfo = [
                'code' => $node['code'],
                'nodeName' => $node['nodeName'],
                'targetUser' => $node['targetUser'],
                'targetArea' => $node['targetArea'],
                'info' => "{$node['needAll']}|{$node['important']}"
            ];
            $flowList[$node['proId']]['nodes'][] = $nodeInfo;
        }
        return array_values($flowList);
    }

    /**
     * 保存流程
     *
     * @param $mainId
     * @throws \Exception
     * @return bool|true
     *
     * create by ck 20171121
     */
    public function saveFlow($mainId)
    {
        if (!$mainId) {
            throw new \Exception('缺少关联id');
        }
        $data = $this->getInput();
        if (!isset($data['node']) || empty($data['node'])) {
            throw new \Exception('缺少流程节点信息');
        }
        $db = Di::getDefault()->get('db');
        try {
            $db->begin();

            //查询主流程
            $mainFlow = new XhflowMainflow();
            $mainFlow->setSource($this->moduleName);
            $checkMain = $mainFlow->findFirst([
                'conditions' => 'bDelete = 0 AND sTableName = :tableName: AND iContactId = :contactId:',
                'bind' => ['tableName' => $this->tableName, 'contactId' => $mainId]
            ]);

            //判断是否需要新建
            if (!$checkMain) {
                $this->createFlow($mainId, $data);
            }

            $db->commit();
            return true;
        } catch (\Exception $e) {
            $db->rollback();
            throw new \Exception($e->getMessage());
        }
    }

    /**
     * 获取提交所需流程信息
     *
     * @param $mainId
     * @return array
     * @throws \Exception
     *
     * create by ck 20171122
     */
    public function getFlowForCommit($mainId)
    {
        if (!$mainId) {
            throw new \Exception('缺少关联id');
        }

        $mainFlow = $this->getMainFlow($mainId);
        $flowNodes = $this->getFlowNodes($mainFlow->iMFId);

        //组装节点
        $flowInfo = $nowInfo = [];
        foreach ($flowNodes as $node) {
            //当前节点
            if ($node->iStatus == 2) {
                $targetUser = array_filter(explode(',', trim($node->sTargetUser, ',')));
                if (!in_array($this->userId, $targetUser)) {
                    throw new \Exception("您不可操作当前<{$node->sName}>节点");
                }
                $nowInfo = [
                    'flowId' => $mainFlow->iMFId,
                    'code' => $node->iCode,
                    'name' => $node->sName,
                    'userIds' => $node->sTargetUser
                ];
                continue;
            }
            //组装未开始数据
            if ($node->iStatus == 1) {
                $flowInfo[$node->iCode] = [
                    'code' => $node->iCode,
                    'name' => $node->sName,
                    'userIds' => $node->sTargetUser,
                    'area' => $node->sTargetArea
                ];
                if ($node->bImportant) {
                    break;
                }
            }
        }
        Main::runUserName($flowInfo, ['userIds' => 'userNames'], true);
        return ['select' => $flowInfo, 'now' => $nowInfo];
    }

    /**
     * 提交流程到下一节点
     * [
     *      保存当前节点意见
     *      判断当前节点状态，处理信息
     *      处理当前节点到下一节点间节点
     *      处理下一节点信息
     *      处理主流程信息
     * ]
     *
     * @param $mainId
     * @param $code
     * @param $advice
     * @param $nextCode
     * @param $userIds
     * @return bool
     * @throws \Exception
     *
     * create by ck 20171127
     */
    public function commit($mainId, $code, $advice, $nextCode, $userIds)
    {
        if (!$mainId) {
            throw new \Exception('缺少主id');
        }
        if (!$code) {
            throw new \Exception('缺少当前流程编号');
        }
        if (!$advice) {
            throw new \Exception('意见不能为空');
        }
        if (!$nextCode) {
            throw new \Exception('提交节点不能为空');
        }
        if (!$userIds) {
            throw new \Exception('缺少用户选择');
        }
        $db = Di::getDefault()->get('db');
        try {
            $db->begin();
            $mainFlow = $this->getMainFlow($mainId);
            $flowNodes = $this->getFlowNodes($mainFlow->iMFId);

            //保存意见
            $adviceObj = new XhflowAdvice();
            $adviceObj->iMFId = $mainFlow->iMFId;
            $adviceObj->iCode = $code;
            $adviceObj->iOperate = 1;
            $adviceObj->sAdvice = $advice;
            if (!$adviceObj->save()) {
                throw new \Exception('意见保存失败：' . implode('|', $adviceObj->getMessages()));
            }

            //处理当前编号节点信息
            $allowNext = false;
            foreach ($flowNodes as $node) {
//                //更改下一节点用户id
//                if ($node->iCode == $nextCode && !$node->bMutable) {
//                    $node->sTargetUser    = ',' . trim($userIds, ',') . ',';
//                    $node->sUnhandledUser = $node->sTargetUser;
//                }
                //非当前节点则跳过
                if ($node->iCode != $code) {
                    continue;
                }

                if ($node->iStatus != 2) {
                    throw new \Exception("当前<{$node->sName}>节点非待处理状态");
                }
                $targetUser = array_filter(explode(',', trim($node->sTargetUser, ',')));
                $handledUser = array_filter(explode(',', trim($node->sHandledUser, ',')));
                $unhandledUser = array_filter(explode(',', trim($node->sUnhandledUser, ',')));
                if (!in_array($this->userId, $targetUser)) {
                    throw new \Exception("您不可操作当前<{$node->sName}>节点");
                }
                if (in_array($this->userId, $handledUser)) {
                    throw new \Exception("您已处理当前<{$node->sName}>节点");
                }
                $handledUser[] = $this->userId;
                unset($unhandledUser[array_search($this->userId, $unhandledUser)]);

                $node->sHandledUser = ',' . implode(',', $handledUser) . ',';
                $node->sUnhandledUser = ',' . implode(',', $unhandledUser) . ',';
                //判断是否进入下一节点
                if (!($node->bNeedAll && $unhandledUser)) {
                    $allowNext = true;
                    $node->iStatus = 3;
                    if (!$node->save()) {
                        throw new \Exception("<{$node->sName}>节点保存失败：" . implode('|', $node->getMessages()));
                    }
                    break;
                }
            }

            //处理下一节点及跳过节点
            if ($allowNext) {
                foreach ($flowNodes as $node) {
                    if ($node->iCode > $code && $node->iCode < $nextCode) {
                        $node->iStatus = 5;
                        if (!$node->save()) {
                            throw new \Exception("<{$node->sName}>节点保存失败：" . implode('|', $node->getMessages()));
                        }
                    }
                    if ($node->iCode == $nextCode) {
                        //更改下一节点用户id
                        if (!$node->sTargetArea) {
                            $node->sTargetUser = ',' . trim($userIds, ',') . ',';
                            $node->sUnhandledUser = $node->sTargetUser;
                        }
                        if (!trim($node->sTargetUser, ',')) {
                            throw new \Exception('下一节点处理人不能为空');
                        }
                        $node->iStatus = 2;
                        if (!$node->save()) {
                            throw new \Exception("<{$node->sName}>节点保存失败：" . implode('|', $node->getMessages()));
                        }

                        //处理主流程完成节点数
                        $mainFlow->iCompleteNum = $nextCode - 1;
                        if (!$mainFlow->save()) {
                            throw new \Exception('主流程保存失败：' . implode('|', $mainFlow->getMessages()));
                        }
                        break;
                    }
                }
            }

            $db->commit();
            return true;
        } catch (\Exception $e) {
            $db->rollback();
            throw new \Exception($e->getMessage());
        }
    }

    /**
     * 创建新流程
     *
     * @param $mainId
     * @param $data
     * @throws \Exception
     * @return bool|true
     *
     * create by ck 20171121
     */
    private function createFlow($mainId, &$data)
    {
        //保存主流程
        $mainFlow = new XhflowMainflow();
        $mainFlow->setSource($this->moduleName);
        $mainFlow->iProId = $data['proId'];
        $mainFlow->sName = $data['proName'];
        $mainFlow->sTableName = $this->tableName;
        $mainFlow->iContactId = $mainId;
        $mainFlow->iNodeNum = count($data['node']);
        if (!$mainFlow->save()) {
            throw new \Exception('主流程保存失败：' . implode('|', $mainFlow->getMessages()));
        }

        //保存流程节点
        $nodeObj = new XhflowFlownode();
        $nodeObj->setSource($this->moduleName);
        foreach ($data['node'] as $code => $node) {
            $info = explode('|', $node['info']);
            $user = ',' . trim($node['user'], ',') . ',';
            $flowNode = new XhflowFlownode();
            $nodeObj->setSource($this->moduleName);
            $flowNode->iMFId = $mainFlow->iMFId;
            $flowNode->iCode = $code;
            $flowNode->sName = $node['name'];
            $flowNode->sTargetUser = $user;
            $flowNode->sHandledUser = '';
            $flowNode->sUnhandledUser = $user;
            $flowNode->bNeedAll = $info[0];
            $flowNode->bImportant = $info[1];
            $flowNode->sTargetArea = $node['area'];
            //初始节点改为待处理
            if ($code == 1) {
                $flowNode->iStatus = 2;
            }
            if (!$flowNode->save()) {
                throw new \Exception('流程节点保存失败：' . implode('|', $flowNode->getMessages()));
            }
        }
        return true;
    }

    /**
     * 根据关联id获取对象
     *
     * @param $mainId
     * @return XhflowMainflow
     * @throws \Exception
     *
     * create by ck 20171124
     */
    private function getMainFlow($mainId)
    {
        if (!$mainId) {
            throw new \Exception('缺少关联id');
        }
        $mainFlow = new XhflowMainflow();
        $mainFlow->setSource($this->moduleName);
        $mainFlow = $mainFlow->findFirst([
            'conditions' => 'bDelete = 0 AND sTableName = :tableName: AND iContactId = :contactId:',
            'bind' => ['tableName' => $this->tableName, 'contactId' => $mainId]
        ]);
        if (!$mainFlow) {
            throw new \Exception('流程不存在');
        }
        return $mainFlow;
    }

    /**
     * 根据主流程id获取节点对象
     *
     * @param $flowId
     * @return XhflowFlownode[]
     * @throws \Exception
     *
     * create by ck 20171124
     */
    private function getFlowNodes($flowId)
    {
        if (!$flowId) {
            throw new \Exception('缺少流程id');
        }
        $flowNodes = new XhflowFlownode();
        $flowNodes->setSource($this->moduleName);
        $flowNodes = $flowNodes->find([
            'conditions' => 'bDelete = 0 AND iMFId = :flowId:',
            'bind' => ['flowId' => $flowId],
            'order' => 'iCode ASC'
        ]);
        if (!$flowNodes) {
            throw new \Exception('流程节点不存在');
        }
        return $flowNodes;
    }

    /**
     * 从post数据获取对应前缀并返回数组
     *
     * @return array
     *
     * create by ck 20170914
     */
    private function getInput()
    {
        $data = [];
        foreach ($_POST as $key => $value) {
            if (strpos($key, self::NamePrefix) === 0) {
                $data[substr($key, strlen(self::NamePrefix))] = $value;
            }
        }
        return $data;
    }

    /**
     * 根据关联id获取权限
     *
     * @param $mainId
     * @return array
     * @throws \Exception
     *
     * create by ck 20171129
     */
    public function getPower($mainId)
    {
        $mainFlow  = $this->getMainFlow($mainId);
        $flowNode  = new XhflowFlownode();
        $flowNode->setSource($this->moduleName);
        $flowNode = $flowNode->findFirst([
            'conditions' => 'bDelete = 0 AND iMFId = :flowId: AND iStatus = 2',
            'bind'       => ['flowId' => $mainFlow->iMFId],
        ]);
        if (!$flowNode) {
            throw new \Exception('当前流程无正进行节点');
        }
        $power = [
            'save'   => false,
            'commit' => false,
            'reject' => false,
            'finish' => false,
            'revoke' => false
        ];
        $targetUser = explode(',', trim($flowNode->sTargetUser, ','));
        if (!in_array($this->userId, $targetUser)) {
            return $power;
        }
        $power['save'] = true;

        //除最后节点都可提交，最后节点可完成
        if ($flowNode->iCode != $mainFlow->iNodeNum) {
            $power['commit'] = true;
        }
        else {
            $power['finish'] = true;
        }

        //除第一个节点都可退回，第一节点可撤回
        if ($flowNode->iCode > 1) {
            $power['reject'] = true;
        }
        else {
            $power['revoke'] = true;
        }
        return $power;
    }

    public function getFlow($mainId)
    {
        $mainFlow  = $this->getMainFlow($mainId);
        $flowNodes = $this->getFlowNodes($mainFlow->iMFId);

    }

}